#This file contains all classes involved with handling word counts

import Post
import OversamplingWeights

#Keeps track of how many times a particular word has occured in each status.
class Word:
	#Increments the count for the given status
	def increment(self, postStatus):
		if(postStatus == Post.PostStatusEnum.OPEN):
			self.openCount = self.openCount + 1
		elif(postStatus == Post.PostStatusEnum.OFF_TOPIC):
			self.offTopicCount = self.offTopicCount + 1
		elif(postStatus == Post.PostStatusEnum.NOT_CONSTRUCTIVE):
			self.notConstructiveCount = self.notConstructiveCount + 1
		elif(postStatus == Post.PostStatusEnum.NOT_A_REAL_QUESTION):
			self.notARealQuestionCount = self.notARealQuestionCount + 1
		elif(postStatus == Post.PostStatusEnum.TOO_LOCALIZED):
			self.tooLocalizedCount = self.tooLocalizedCount + 1
	
	#Constructor. Calls increment on the status in which the word first occurs
	def __init__(self, word, postStatus):
		self.word = word
		self.openCount = 0
		self.offTopicCount = 0
		self.notConstructiveCount = 0
		self.notARealQuestionCount = 0
		self.tooLocalizedCount = 0
		self.increment(postStatus)
	
	#Gets the probability of the status using default weights (all ones)
	def getProbabilityOfStatus(self, postStatus):
		return self.getProbabilityOfStatusWithWeights(postStatus, OversamplingWeights.Weights(1,1,1,1,1))
		
	#Gets the probability of the status using the given weights.
	#The probability of a status is the status count divided by the total count.
	def getProbabilityOfStatusWithWeights(self, postStatus, weights):
		return float(self.getCountByStatusWithWeights(postStatus, weights)) / float(self.totalCountWithWeights(weights))
	
	#Gets the number of times a word occured using the default weights (all ones)
	def getCountByStatus(self, postStatus):
		return getCountByStatusWithWeights(postStatus, OversamplingWeights.Weights(1,1,1,1,1))
	
	#Gets the number of times a word occured using the given weights.
	#Each status has its own weight which indicates how many times words of that status should be counted
	def getCountByStatusWithWeights(self, postStatus, weights):
		if(postStatus == Post.PostStatusEnum.OPEN):
			return self.openCount * weights.getWeightByStatus(Post.PostStatusEnum.OPEN)
		elif(postStatus == Post.PostStatusEnum.OFF_TOPIC):
			return self.offTopicCount * weights.getWeightByStatus(Post.PostStatusEnum.OFF_TOPIC)
		elif(postStatus == Post.PostStatusEnum.NOT_CONSTRUCTIVE):
			return self.notConstructiveCount * weights.getWeightByStatus(Post.PostStatusEnum.NOT_CONSTRUCTIVE)
		elif(postStatus == Post.PostStatusEnum.NOT_A_REAL_QUESTION):
			return self.notARealQuestionCount * weights.getWeightByStatus(Post.PostStatusEnum.NOT_A_REAL_QUESTION)
		elif(postStatus == Post.PostStatusEnum.TOO_LOCALIZED):
			return self.tooLocalizedCount * weights.getWeightByStatus(Post.PostStatusEnum.TOO_LOCALIZED)
		sys.exit("should never reach here")
	
	#Gets the total count using default weights (all ones)
	def totalCount(self):
		return self.totalCountWithWeights(OversamplingWeights.Weights(1,1,1,1,1))
	
	#Gets the total count using the given weights
	def totalCountWithWeights(self, weights):
		total = 0
		total += self.openCount * weights.getWeightByStatus(Post.PostStatusEnum.OPEN)
		total += self.offTopicCount * weights.getWeightByStatus(Post.PostStatusEnum.OFF_TOPIC)
		total += self.notConstructiveCount * weights.getWeightByStatus(Post.PostStatusEnum.NOT_CONSTRUCTIVE)
		total += self.notARealQuestionCount * weights.getWeightByStatus(Post.PostStatusEnum.NOT_A_REAL_QUESTION)
		total += self.tooLocalizedCount * weights.getWeightByStatus(Post.PostStatusEnum.TOO_LOCALIZED)
		return total
	
	#Prints the word bag out as a string for debug purposes.
	def toString(self):
		return self.word + ": " + str(self.openCount) + " " + str(self.offTopicCount) + " " + str(self.notConstructiveCount) + " " + str(self.notARealQuestionCount) + " " + str(self.tooLocalizedCount)
	
	#A word is less than another if it occurs a less number of times. Used to filter out the least occuring words.
	def __lt__(self, other):
		return self.totalCount() < other.totalCount()

#A collection of all words (and the number of times they occur in each status)
class WordBag:
	#Constructor
	def __init__(self):
		self.words = {}
	
	#Returns true if a word is present in the wordbag
	def contains(self,word):
		return word in self.words
		
	#Gets a particular word object out of the wordbag
	def get(self,word):
		return self.words[word]
	
	#Adds a word.
	#This invovles making a new entry if one does not exist or incrementing one that does.
	def add(self, word, postStatus):
		if self.contains(word):
			self.words[word].increment(postStatus)
		else:
			self.words[word] = Word(word, postStatus)
	
	#Gets the total number of unique words in the word bag.
	def getNumberOfWords(self):
		return len(self.words)
	
	#Prints the top words
	def printTopWords(self, numWords):
		wordList = self.words.values()
		wordList.sort(reverse=True)
		for index in range(0,numWords,1):
			print wordList[index].toString()
	
	#Drops all words that occur less times than the specified threshold
	def dropLeastOccuringWords(self, threshold):
		for wordKey in self.words.keys():
			if (self.words[wordKey].totalCount() <= threshold):
				del self.words[wordKey]